package com.jinly.ryder.ssh.web;

import com.jinly.ryder.account.web.utils.AuthUtil;
import com.jinly.ryder.common.auth.annotation.Auth;
import com.jinly.ryder.common.auth.model.AuthRole;
import com.jinly.ryder.common.auth.model.AuthType;
import com.jinly.ryder.common.error.SystemErrorType;
import com.jinly.ryder.common.utils.FileUtil;
import com.jinly.ryder.manage.service.AppInfoService;
import com.jinly.ryder.manage.service.AppInstanceService;
import com.jinly.ryder.manage.service.HostInstanceService;
import com.jinly.ryder.manage.service.model.AppInfo;
import com.jinly.ryder.manage.service.model.AppInstance;
import com.jinly.ryder.manage.service.model.HostInstance;
import com.jinly.ryder.manage.service.model.setting.LogSetting;
import com.jinly.ryder.ssh.command.model.FileInfo;
import com.jinly.ryder.ssh.service.SshFileService;
import com.jinly.ryder.ssh.web.vo.FileInfoVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@Slf4j
@RestController
@RequestMapping("/sshFile")
@RequiredArgsConstructor
public class SshFileController {

    private final AppInfoService appInfoService;
    private final SshFileService sshFileService;
    private final HostInstanceService hostInstanceService;
    private final AppInstanceService appInstanceService;

    @GetMapping("/list")
    @Auth(type = AuthType.MANAGE, role = AuthRole.ADMIN, value = "admin")
    public List<FileInfoVO> list(Integer hostId, String dir) {
        HostInstance hostInstance = hostInstanceService.getInstance(hostId);
        if (hostInstance != null) {
            List<FileInfo> list = sshFileService.fileList(hostInstance.getHost(), 22, dir);
            return list.stream().map(f -> {
                FileInfoVO fileInfoVO = new FileInfoVO();
                BeanUtils.copyProperties(f, fileInfoVO);
                return fileInfoVO;
            }).collect(Collectors.toList());
        }
        return null;
    }

    @GetMapping("/download")
    @Auth(type = AuthType.MANAGE, role = AuthRole.ADMIN, value = "admin")
    public void download(Integer hostId, String fileName, HttpServletResponse response) {
        checkFileName(fileName);
        HostInstance hostInstance = hostInstanceService.getInstance(hostId);
        if (hostInstance != null) {
            downloadFile(fileName, hostInstance.getHost(), response);
        }
    }

    private void downloadFile(String fileName, String host, HttpServletResponse response) {
        File file = null;
        File zipFile = null;
        String tempDir = System.getProperty("java.io.tmpdir") + "/download/" + UUID.randomUUID().toString();
        try {
            file = new File(tempDir + "/" + new File(fileName).getName());
            FileUtil.createDir(file.getParentFile().getPath());
            file.createNewFile();
            long l1 = System.currentTimeMillis();
            sshFileService.getFile(host, 22, fileName, file.getPath());
            long l2 = System.currentTimeMillis();
            log.info("拉取下载文件完成,大小:{}，耗时:{}ms", file.length(), (l2 - l1));
            //设置响应头和客户端保存文件名
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/force-download");
            if (file.length() > (1 * 1014 * 1024)) {
                zipFile = FileUtil.zipFile(file);
                long l3 = System.currentTimeMillis();
                log.info("压缩下载文件完成,大小:{}，耗时:{}ms", zipFile.length(), (l3 - l2));
                response.setHeader("Content-Disposition", "attachment;fileName=" + zipFile.getName());
                FileUtil.fileWrite(zipFile, response.getOutputStream());
            } else {
                response.setHeader("Content-Disposition", "attachment;fileName=" + file.getName());
                FileUtil.fileWrite(file, response.getOutputStream());
            }
            long l4 = System.currentTimeMillis();
            log.info("下载文件完成,耗时:{}ms", (l4 - l1));
        } catch (Exception e) {
            log.error("下载失败", e);
            SystemErrorType.INTERNAL_SERVER_ERROR.throwError();
        } finally {
            FileUtil.delete(tempDir);
        }
    }

    @GetMapping("/list/appInstanceLog")
    public List<FileInfoVO> appInstanceLogList(Integer appInstanceId, String dir) {
        AppInstance appInstance = appInstanceService.get(appInstanceId);
        Assert.notNull(appInstance, "实例不存在");
        AuthUtil.check(AuthType.APP, appInstance.getAppName(), AuthRole.DEVELOPER);
        HostInstance hostInstance = hostInstanceService.getHostInstance(appInstance.getHost());
        if (hostInstance != null) {
            AppInfo appInfo = appInfoService.getAppInfo(appInstance.getAppName());
            LogSetting logSetting = appInfo.getLogSetting();
            if (logSetting != null && !ObjectUtils.isEmpty(logSetting.getRootPath())) {
                String root = logSetting.getRootPath();
                if (dir == null || "/".equals(dir)) {
                    dir = root;
                }
                if (!dir.startsWith(root)) {
                    SystemErrorType.BAD_REQUEST.throwError("路径错误");
                }
                List<FileInfo> list = sshFileService.fileList(hostInstance.getHost(), 22, dir);
                return list.stream().map(f -> {
                    FileInfoVO fileInfoVO = new FileInfoVO();
                    BeanUtils.copyProperties(f, fileInfoVO);
                    return fileInfoVO;
                }).collect(Collectors.toList());
            }
        }
        return null;
    }

    @GetMapping("/download/appInstanceLog")
    public void appInstanceLogDownload(Integer appInstanceId, String fileName, HttpServletResponse response) {
        checkFileName(fileName);
        AppInstance appInstance = appInstanceService.get(appInstanceId);
        Assert.notNull(appInstance, "实例不存在");
        AuthUtil.check(AuthType.APP, appInstance.getAppName(), AuthRole.DEVELOPER);
        HostInstance hostInstance = hostInstanceService.getHostInstance(appInstance.getHost());
        if (hostInstance != null) {
            AppInfo appInfo = appInfoService.getAppInfo(appInstance.getAppName());
            LogSetting logSetting = appInfo.getLogSetting();
            if (logSetting != null && !ObjectUtils.isEmpty(logSetting.getRootPath())) {
                String root = logSetting.getRootPath();
                if (!fileName.startsWith(root)) {
                    SystemErrorType.BAD_REQUEST.throwError("路径错误");
                }
                downloadFile(fileName, hostInstance.getHost(), response);
            }
        }
    }

    private void checkFileName(String fileName) {
        if (fileName.indexOf("./") != -1) {
            SystemErrorType.BAD_REQUEST.throwError();
        }
    }
}
